/**
 * @file MainWindow.cpp
 *
 * Implementation of class MainWindow.
 *
 * @author Markus Haecker
 * @date 2010-04-14
 *
 * @todo Check support for (german) special chars after I18n implementation.
 */

#include "MainWindow.h"
#include "SceneFactory.h"

/**
 * Constructor of class MainWindow.
 * The class is derived from the base class QMainWindow (public).
 * The layout has been created with Qt Designer and is loaded from file MainWindow.ui.
 *
 * @param[in] file String with a file to load, may be empty (default = "").
 * @param[in] parent Parent widget (default = 0).
 */
MainWindow::MainWindow(QString fileToOpen, QWidget* parent)
    : QMainWindow(parent)
{
	ui.setupUi(this);
	setWindowIcon(QIcon(":/img/offview.png"));

	scene = 0;
	glWidget = new GlWidget();
	setCentralWidget(glWidget);

	showMenuRenderModes();
	syncMenu();
	connectSignalsAndSlots();

	statusBar()->showMessage(tr("Welcome"));

	// If a file was given as command line argument, try to parse it
	if (!fileToOpen.isEmpty()) {
		parseFileAndShowObject(fileToOpen);
	}
}

/**
 * Destructor of MainWindow.
 */
MainWindow::~MainWindow()
{
	delete renderModesAlignmentGroup;

	for (int i = 0; i < actionRenderMode.size(); ++i) {
		delete actionRenderMode.at(i);
	}
}

/**
 * Open, parse and show an OFF-File.
 * @param[in] fileToOpen Path and name of the OFF-File.
 */
void MainWindow::parseFileAndShowObject(const QString & fileToOpen)
{
	try {
		IScene* newScene = SceneFactory::openFile(fileToOpen);

		glWidget->setScene(0);
		if (scene) {
			delete scene;
		}
		scene = newScene;
		glWidget->setScene(scene);
		syncMenu();
	}
	catch(QString & message) {
		QMessageBox::warning(this, tr("Error"), tr("An error occured while "
				"processing file ") + fileToOpen + "<br><br>" + message);
	}
}

/**
 * This is just a temporary method that prompts a MessageBox while calling an
 * unimplemented menu item.
 */
void MainWindow::notYet()
{
	QMessageBox::information(this, tr("Not yet implemented..."),
			tr("That's something we have to work on."));
}

/**
 * Assign menu items (generated from MainWindow.ui) to functions (slots).
 * Menu items for choosing a render mode are generated by showMenuRenderModes().
 */
void MainWindow::connectSignalsAndSlots()
{
    connect(ui.actionOpen_File,	SIGNAL(triggered()), this, SLOT(open()));
    connect(ui.actionClose_File, SIGNAL(triggered()), this, SLOT(close()));
    connect(ui.actionExit, SIGNAL(triggered()), this, SLOT(exit()));
    connect(ui.actionXz_Plane, SIGNAL(triggered()), this, SLOT(toggleXzPlane()));
    connect(ui.actionXy_Plane, SIGNAL(triggered()), this, SLOT(toggleXyPlane()));
    connect(ui.actionYz_Plane, SIGNAL(triggered()), this, SLOT(toggleYzPlane()));
    connect(ui.actionChoose_Background_Color, SIGNAL(triggered()), this,
			SLOT(setBackgroundColor()));
    connect(ui.actionChoose_Object_Color, SIGNAL(triggered()), this,
			SLOT(setObjectColor()));
    connect(ui.actionShow_Coordinate_System, SIGNAL(triggered()), this,
			SLOT(toggleAxes()));
    connect(ui.actionReset_View, SIGNAL(triggered()), this, SLOT(resetView()));
    connect(ui.actionGerman, SIGNAL(triggered()), this, SLOT(setLanguageGerman()));
    connect(ui.actionEnglish, SIGNAL(triggered()), this, SLOT(setLanguageEnglish()));
    connect(ui.actionHelp_Content, SIGNAL(triggered()), this, SLOT(help()));
    connect(ui.actionAbout_OffView, SIGNAL(triggered()), this, SLOT(about()));
    connect(ui.actionAbout_Qt, SIGNAL(triggered()), this, SLOT(aboutQt()));
}

/**
 * Display all available render modes in menu "View" -> "Mode".
 * The render modes are provided in a QStringList by listRenderModes().
 * Render modes are shown in an alignment group, each one with a radio button,
 * so that only one mode can be marked as active.
 * Render mode items are connected with setRenderMode(), which is competent
 * to initiate the mode change.
 */
void MainWindow::showMenuRenderModes()
{
	QStringList nameOfRenderModes = glWidget->listRenderModes();

	int numberOfRenderModes = nameOfRenderModes.size();
	renderModesAlignmentGroup = new QActionGroup(this);

	for (int i = 0; i < numberOfRenderModes; ++i) {
		actionRenderMode.append(new QAction(nameOfRenderModes.at(i), this));
		actionRenderMode[i]->setCheckable(true);
		connect(actionRenderMode[i], SIGNAL(toggled(bool)), this, SLOT(setRenderMode()));

		renderModesAlignmentGroup->addAction(actionRenderMode[i]);
		ui.menuMode->addAction(actionRenderMode[i]);
	}

	int renderMode = glWidget->renderMode();
	actionRenderMode[renderMode]->setChecked(true); // Mark radio button of active mode
}

/**
 * Shows an "Open File" dialog.
 * Users can select an *.off file. After clicking "open" it is attempted to open
 * and parse the file and show the 3D model in the window.
 */
void MainWindow::open()
{
	QString file = QFileDialog::getOpenFileName(
	         this, tr("Open File"),
	         QDir::homePath(), SceneFactory::openFileString());

	if(!file.isNull()) {
		parseFileAndShowObject(file);
	}
}

/**
 * Clear the window, vanishs any 3D model shown in it.
 */
void MainWindow::close()
{
	glWidget->setScene(0);
	if (scene)
		delete scene;
	scene = 0;
	syncMenu();
}

/**
 * Tells the application to exit.
 */
void MainWindow::exit()
{
	QApplication::exit();
}

/**
 * Coming soon...
 */
void MainWindow::setBackgroundColor()
{
	QColor color = glWidget->backgroundColor();
	color = QColorDialog::getColor(color, this, tr("Choose background color"));
	if (color.isValid()) {
		glWidget->setBackgroundColor(color);
	}
}

/**
 * Coming soon...
 */
void MainWindow::setObjectColor()
{
	QColor color = glWidget->objectColor();
	color = QColorDialog::getColor(color, this, tr("Choose object color"));
	if (color.isValid()) {
		glWidget->setObjectColor(color);
	}
}

/**
 * Coming soon...
 */
void MainWindow::resetView()
{
	glWidget->resetView();
	syncMenu();
}

/**
 * Coming soon...
 */
void MainWindow::toggleAxes()
{
	if (ui.actionShow_Coordinate_System->isChecked()) {
		glWidget->setAxes(true);
	} else {
		glWidget->setAxes(false);
	}
}

/**
 * Coming soon...
 */
void MainWindow::toggleXzPlane()
{
	if (ui.actionXz_Plane->isChecked()) {
		glWidget->setXzPlane(true);
	} else {
		glWidget->setXzPlane(false);
	}
}

/**
 * Coming soon...
 */
void MainWindow::toggleXyPlane()
{
	if (ui.actionXy_Plane->isChecked()) {
		glWidget->setXyPlane(true);
	} else {
		glWidget->setXyPlane(false);
	}
}

/**
 * Coming soon...
 */
void MainWindow::toggleYzPlane()
{
	if (ui.actionYz_Plane->isChecked()) {
		glWidget->setYzPlane(true);
	} else {
		glWidget->setYzPlane(false);
	}
}

/**
 * Synchronize the menu's check buttons.
 * Set or unset the check buttons in menus "Show Planes" and "Show Coordinate
 * System", depending on the values returned by the GLWidget-methods.
 *
 * Values are set initial in GlWidget::resetView().
 */
void MainWindow::syncMenu()
{
	ui.actionShow_Coordinate_System->setChecked(glWidget->axes());
	ui.actionXz_Plane->setChecked(glWidget->xzPlane());
	ui.actionXy_Plane->setChecked(glWidget->xyPlane());
	ui.actionYz_Plane->setChecked(glWidget->yzPlane());
}

/**
 * Coming soon...
 */
void MainWindow::help()
{
	QString path = QString("file:///") + 
		QApplication::applicationDirPath() + tr("/help_en.html");	
	QDesktopServices::openUrl(QUrl(path));
}

/**
 * Set new render mode.
 * In the menu bar there is a dynamically generated menu for changing the
 * render mode. Available render modes are shown as radio buttons. If the user
 * select one, this function checks which it was and update the window.
 *
 * @see void GlWidget::setRenderMode(int)
 */
void MainWindow::setRenderMode()
{
	for (int i = 0; i < actionRenderMode.size(); ++i) {
		if (actionRenderMode.at(i)->isChecked()) {
			glWidget->setRenderMode(i);
			break;
		}
	}
	statusBar()->showMessage(glWidget->renderModeName() + tr(" activated"));
}

/**
 * Displays a simple message box about our cool viewer...
 */
void MainWindow::about()
{
	QString body = tr("<h3>About OffView version %1</h3>"
			"<p>This program is for viewing Object File Format (.off) files in 3D "
			"with OpenGL.</p>"
			"<p>Object File Format files are used to represent the geometry of a "
			"model by specifying the polygons of the model's surface. The "
			"polygons can have any number of vertices.</p>"
			"<p>OffView is written by four students of software engineering at "
			"Konstanz University of Applied Sciences, Germany:</p>"
			"<ul>"
			"<li>Manuel Caputo,</li>"
			"<li>Markus Haecker,</li>"
			"<li>Daniel Fritz and</li>"
			"<li>Benjamin Stauder.</li>"
			"</ul>"
			"<p>The project is hosted on Google Code and can be found under "
			"<a href=\"http://code.google.com/p/offview/\">http://code.google.com/p/offview</a>. "
			"It's free software under the conditions of version 3 of the GNU General "
			"Public License (<a href=\"http://www.gnu.org/licenses/gpl-3.0.html\">GPLv3</a>). "
			"</p>").arg(OFFVIEW_VERSION);

	QMessageBox::about(this, tr("About OffView"), body);
}

/**
 * Displays a simple message box about Qt. The message includes the version
 * number of Qt being used by the application.
 */
void MainWindow::aboutQt()
{
	QApplication::aboutQt();
}

/**
 * This method will soon be replaced by a smarter one.
 */
void MainWindow::setLanguageGerman()
{
	QString languageFile = "offview_de_DE";
	QString pathToLanguageFile = QCoreApplication::
			applicationDirPath() + "/lang";

	if (!translator.load(languageFile, pathToLanguageFile)) {
		QMessageBox::warning(this, tr("Error"), tr("Couldn't load language "
				"file ") + pathToLanguageFile + "/" + languageFile);
	} else {
		QCoreApplication::installTranslator(&translator);
		ui.retranslateUi(this);
	}
}

/**
 * This method will soon be replaced by a smarter one.
 */
void MainWindow::setLanguageEnglish()
{
	QCoreApplication::removeTranslator(&translator);
	ui.retranslateUi(this);
}
